import java.util.*;

public class Correlation {
	
	protected ArrayList<Double> meanValues = null;
	protected ArrayList<Double> outputs = null;
	protected List<RankedCorrelation> coeficient = null;
	
	private Correlation()
	{
		
	}
	
	private static Correlation instance = null;
	
	public static Correlation GetInstance()
	{
		if(instance == null)
			instance = new Correlation();
		return instance;
	}
	
	public class RankedCorrelation implements Comparator<RankedCorrelation>, Comparable<RankedCorrelation>
	{
		public int column;
		public Double correlation;
		
		public RankedCorrelation(int index, Double value)
		{
			column = index;
			correlation = value;
		}
		
		public int compare(RankedCorrelation o1, RankedCorrelation o2) {
			if(o1.correlation == o2.correlation)
				return 0;
			else if(o1.correlation < o2.correlation )
				return -1;					
			return 1;
		}

		public int compareTo(RankedCorrelation o) {
			if(this.correlation == o.correlation)
				return 0;
			else if(this.correlation < o.correlation )
				return -1;					
			return 1;
		}
	}
	
	private void CalculateMeanValue(Matrix matrix)
	{
		if(meanValues != null)
			meanValues.clear();
		meanValues = new ArrayList<Double>(matrix.getColumnSize());
		
		if(outputs != null)
			outputs.clear();
		outputs = new ArrayList<Double>(matrix.getColumnSize());
		
		for(int i = 0; i < matrix.getColumnSize(); i++)
		{
			MatrixColumnIterator iterator = matrix.getColumIterator(i);
			Double value = new Double(0);
			Double accumulator = new Double(0);
			while(iterator.hasNext())
			{
				value = iterator.next();
				accumulator += value;
				if(i == 0)
					outputs.add(value);
			}
			meanValues.add( accumulator / matrix.getRowSize());
		}		
	}
		
	public void doCorrelation(Matrix matrix)	
	{
		if(coeficient != null)
			coeficient.clear();
		
		coeficient = new ArrayList<RankedCorrelation>(matrix.getColumnSize());
		CalculateMeanValue(matrix);
		
		for(int i = 1; i < matrix.getColumnSize(); i++)
		{
			MatrixColumnIterator iterator = matrix.getColumIterator(i);
			Double value = new Double(0);
			Double numerator = new Double(0);
			Double denominator = new Double(0);
			Double valueX = new Double(0);
			Double valueY = new Double(0);
			
			
			while(iterator.hasNext())
			{
				value = iterator.next();
				valueX = value - meanValues.get(i);
				valueY = outputs.get(i) - meanValues.get(0);
				numerator +=  valueX * valueY;
				denominator += Math.pow(valueX, 2) * Math.pow(valueY, 2); 
			}
			RankedCorrelation rank = new RankedCorrelation(i, numerator / Math.sqrt(denominator)); 
			coeficient.add(rank);					
		}
		Collections.sort(coeficient);
	}
	
	public int getOrder(Row left, Row right)
	{
		int i = 0, toReturn = 0;
		
		while(i < left.size() && toReturn == 0)
		{
		 	int index = coeficient.get(i).column; 
			if(left.get(index) == right.get(index))
				i++;
			else if(left.get(index) < right.get(index))
				toReturn = 1;
			else
				toReturn = -1;
		}
		return toReturn;
	}
	
	

}

